import React from 'react';
import {
  message,
  Radio,
  Select,
  Popover
} from 'antd';
import config from 'config';
import httpFetch from 'share/httpFetch';
import errorMessage from 'share/errorMessage';
import { messages } from "share/common";
import moment from 'moment';
import RSCService from 'containers/data-center/report/travel-report/report-search-components.service';

import axios from 'axios';
import CostCenterItemSelectForReport
  from "./components/cost-center-item-select-for-report/index";
import ExpenseTypeSelectForReport
  from "./components/expense-type-select-for-report/index";
import NewCostCenterSelector from "./components/new-cost-center-selector";
import FormTypeSelector from "./components/form-type-selector";
import expBagCode from 'containers/financial-management/new-finance-audit/searchForm-components/expBagCode'
import departmentObj from 'containers/financial-management/new-finance-audit/searchForm-components/department'
import PayeeTypeAndIdSelector from "./components/payee-type-and-id-selector/index"
import LabelsSelector from "./components/labels-selector";
import Selector from 'components/multi-selector'
import { labelsSelectorHasValue, labelsSelectorTagParser, labelsSelectorTransfer } from "./components/labels-selector";

const Option = Select.Option;

// http响应拦截器
axios.interceptors.response.use(data => {
  return fixTask24211(data);
}, error => {
  return Promise.reject(error)
});

/**
 * 任务id 24211
 * 对接口返回的数据 额外加数据
 *
 * 似乎是某报表需要前端添加额外的报销单类型
 * @param data
 * @returns {*}
 */
function fixTask24211(data) {
  if (data.config.url.match('/api/custom/forms/setOfBooks/all') && data.config.data.match('0000') && data.data && data.data.length >= 0) {
    let obj = {};
    obj.formOID = "0000";
    obj.formName = messages('finance-7.key277')/*消费商(公司支付)*/;
    data.data.push(obj)
  }
  return data;
}

//查询时间规则：默认是当月：本月1号到目前，最多查询三个月
export const today = new Date();
export const todayYear = today.getFullYear();
export const currentTime = moment(today);
export const currentTimeBeforeThree = moment().subtract('month', 1);
// 获取当前默认帐套
export function getBooksDefaultValue(context) {
  const {setOfBooksName, baseCurrency, setOfBooksId} = (context.props.company || {});
  return {
    setOfBooksName_functionalCurrencyCode: setOfBooksName + "/" + baseCurrency,
    setOfBooksId
  }
}

// 检查是否超过12个月
export function checkDateDuration(startDate, endDate) {
  if (!startDate || !endDate) return true;
  startDate = moment(startDate);
  endDate = moment(endDate);
  let startYear = startDate.get("year"),
    startMonth = startDate.get("month"),
    endYear = endDate.get("year"),
    endMonth = endDate.get("month");
  return (endYear * 12 + endMonth) - (startYear * 12 + startMonth) > 12
}

const {
  getValueListCommon,
  getPopularCityV2,
  getReceiptLabelTypes,
  getformTypeList,
  getValueCurrency,
  getErStatus,
  getExpenseLabels,
  getDocLabels,
  getInvoiceType
} = RSCService;

/**
 * 写在这里一个比较重要的注释
 * 后端不管是更改criteriaCode，还是criteriaPropName，一定要与前端沟通
 * 不然有问题一定甩给后端
 *
 * criteriaPropName一个比较常见的影响的点就是 supportMultipleArr 这个数组
 */
export default {
  dependencyMap: {},  // 以被依赖项code为key，值为依赖项的code数组，例如company和currency依赖于books，则books: ['company', 'currency']
  codeToName: {},
  nameToCode: {},
  codeToDependency: {}, // 当前项code => 依赖的项的code
  nameToLabel: {},

  // 每次进入新的报表时清空之前保存的map
  resetMaps() {
    this.dependencyMap = {};
    this.codeToName = {};
    this.nameToCode = {};
    this.codeToDependency = {};
    this.nameToLabel = {};
  },

  /**
   *
   * @param list  接口返回的源筛选器列表
   * @param context
   * @param searchFormItem  获取单个searchFormItem时需要传入原searchFormItem
   * @param changeParams  级联更新时需要传入当前更新的值
   * @returns {*}
   */
  searchFormFactory({ list, context, searchFormItem, changeParams }) {
    // 简单的选择类型的筛选器生成方法
    function commonSelectFactory({ getParams, multiple, getMethod, params={} }) {
      return multiple ? ({ label, id }) => {
        return {
          label,
          id,
          component: 'MultiSelectorV2',
          props: {
            selectorItem: {
              service: () => (getMethod || getValueListCommon)(getParams, params),
              label: 'label',
              key: 'value'
            },
          },
          parser: value => {
            if (value && value.length) {
              return { [id]: value.map(item => item.value) }
            }
            return { [id]: undefined }
          }
        }
      } : ({ label, id }) => {
        return {
          label,
          id,
          component: 'Selector',
          props: {
            selectorItem: {
              service: () => (getMethod || getValueListCommon)(getParams, params),
              label: 'label',
              key: 'value'
            }
          }
        }
      }
    }

    // 简单筛选器的通用生成方法
    function commonComponentFactory(component = 'Input', parser, formatter) {
      let placeholder;
      if (component === 'Input') {
        placeholder = messages('common.please.input')/*请输入*/;
      }
      return function ({ label, id }) {
        return {
          label,
          id,
          component,
          props: {
            parser,
            formatter,
            placeholder
          }
        }
      }
    }

    // 通用LabelsSelector筛选器生成方法
    function commonLabelsSelectorFactory(getMethod) {
      return ({ label, id }) => {
        let selectorItem = {
          service: () => getMethod(),
          label: 'label',
          key: 'value'
        };
        return {
          id,
          label,
          component: <LabelsSelector
            selectorItem={selectorItem}
          />,
          hasValue: labelsSelectorHasValue,
          tagParser: labelsSelectorTagParser,
        }
      }
    }

    // 通用Select及Radio等antd组件tagParser
    function commonTagParser(rowChildren) {
      return value => (rowChildren.find(item => item.value === value) || {}).label
    }

    // 通用多选筛选器tagParser
    function commonMultipleTagParser(labelKey = 'name') {
      return value => {
        if (value.length) {
          let firstLabel = value[0][labelKey];
          let valueLength = value.length;
          return valueLength === 1 ? firstLabel : messages('finance-7.key304',{arg1: firstLabel,arg2: valueLength})/*{arg1} 等{arg2}条*/;
        } else if (value) {
          return value[labelKey]
        }
        return ""
      }
    }

    // 依赖帐套的筛选器获取当前帐套id及placeholder的方法
    const setOfBooksIdAndPlaceholderFactory = (context) => {
      let { advancedTableRef } = context;
      let setOfBooksId = getBooksDefaultValue(context).setOfBooksId;

      // 直接从advancedTableRef取值，似乎取不到，或者是修改之前的值
      if (advancedTableRef) {
        let setOfBooksIdWrapper = advancedTableRef.getFieldValue(this.codeToName.books || 'set_of_books_id');
        if (setOfBooksIdWrapper && setOfBooksIdWrapper[0]) {
          setOfBooksId = setOfBooksIdWrapper[0].setOfBooksId;
        }
      }

      // 从修改值中取值
      if (changeParams && changeParams[0]) {
        setOfBooksId = changeParams[0].setOfBooksId;
      }

      let placeholder = setOfBooksId ? messages('common.select')/*请选择*/ : messages('finance-7.key154')/*请先选择账套*/
      return {
        setOfBooksId,
        placeholder
      }
    };

    // 通用dateRangePicker的[parser, formatter]
    const dateParserAndFormatter = [
      arr => arr ? arr.map(value => value ? moment(value) : undefined) : [],
      (start, end) => {
        if (!start && !end) return undefined;
        return [start ? start.format('YYYY-MM-DD') : undefined, end ? end.format('YYYY-MM-DD') : undefined]
      }
    ];

    // 当前报表私有逻辑载体
    const { currentReportPrivate } = context.state;
    const {
      searchItemHandler = {},
      searchItemInitialValue = {},
      searchItemInitialValueByName = {}
    } = currentReportPrivate;
    const { searchFormInitialValueFactory, cascadeHandler } = this;
    const langCode = context.props.language.code;

    const DEFAULT_CODE_LIST = [
      'manual_input', 'approver_title', 'approver_duty', 'cost_center_item_code_from', 'cost_center_item_code_to',
      'drawee', 'departure_hot_city', 'hot_city', 'business_code', 'receipt_num', 'receipt_code',
      'manual_input_like',
      //自定义报表后 可能会加的
      'car_type', 'reject_type', 'take_taxi_way', 'expense_type_category', 'year_month_day_date',
      'toll_type', 'toll_zero_tax_flag'


    ]; // 使用默认输入组件的code，这里仅做记录，最终使用的是DEFAULT_CODE_MAP.default

    /**
     * code to search item
     *
     * To:(收不到的)袁梦大佬
     * 受小弟一拜！！！！！！ DEFAULT_CODE_MAP  太强了！！！！    ---欧阳柯
     */
    const DEFAULT_CODE_MAP = {
      'date': commonComponentFactory('DateRangePicker', ...dateParserAndFormatter),
      'date_month': ({ label, id }) => {
        return {
          label,
          id,
          component: 'DateRangePicker',
          props: {
            component: 'MonthPicker',
            format: 'YYYY-MM',
            parser: arr => arr ? arr.map(value => value ? moment(value) : undefined) : [],
            formatter: (start, end) => [start ? start.format('YYYY-MM') : undefined, end ? end.format('YYYY-MM') : undefined]
          }
        }
      },
      'slave_date_default': commonComponentFactory('DateRangePicker', ...dateParserAndFormatter),
      'slave_date': commonComponentFactory('DateRangePicker', ...dateParserAndFormatter),
      'single_date': commonComponentFactory('DatePicker'),
      'year_month_date': commonComponentFactory('MonthPicker'),
      'year': ({ label, id }) => {
        // 租户创建那一年至今或20年前至今
        let tenantFromFeeReport = context.props.tenant;
        let startYear = (new Date(tenantFromFeeReport.createdDate)).getFullYear();
        let length = startYear ? todayYear - startYear + 1 : 20;
        let children = new Array(length).fill(1).map((val, index) => {
          let year = todayYear - index;
          return <Option key={year}>{year}</Option>
        });
        return {
          label,
          id,
          component: 'Select',
          props: {
            style: { width: '100%' },
            placeholder: messages('common.select')/*请选择*/
          },
          children,
          tagParser: value => value
        }
      },
      'cost_center_item_status': ({ label, id }) => {
        const rowChildren = [
          { label: messages('common.all')/*全部*/, value: 'all' },
          { label: messages('common.valid')/*生效*/, value: 'enable' },
          { label: messages('common.invalid')/*失效*/, value: 'disable' },
        ];
        const children = rowChildren.map((option) => {
          return <Radio value={option.value} key={option.value}>{option.label}</Radio>
        });
        return {
          label,
          id,
          component: 'RadioGroup',
          children,
          tagParser: commonTagParser(rowChildren)
        }
      },
      'city': commonSelectFactory({ getMethod: getPopularCityV2, getParams: langCode }),
      'receipt_label_types': commonSelectFactory({ getMethod: getReceiptLabelTypes, multiple: true }),
      'is_vat_invoice': ({ label, id }) => {
        const rowChildren = [
          {
            label: messages('common.yes')/*是*/,
            value: "1"
          },
          {
            label: messages('common.no')/*否*/,
            value: "0"
          },
          {
            label: messages('common.all')/*全部*/,
            value: '2'
          },
        ];
        const children = rowChildren.map(item => <Option key={item.value}>{item.label}</Option>);
        return {
          label,
          id,
          component: 'Select',
          props: {
            style: { width: '100%' },
            placeholder: messages('common.select')/*请选择*/
          },
          children,
          tagParser: commonTagParser(rowChildren)
        }
      },
      'airPlusCode': ({ label, id }) => {
        let tenantId = context.props.tenant.id;
        let selectorItem = {
          url: `${config.baseUrl}/vendor-data-service/api/company/companyCode/query?tenantId=${tenantId}`,
          label: 'code',
          key: 'code',
          listKey:'body',
          offlineSearchMode: true,
        };
        return {
          component: (
            <Selector
              selectorItem={selectorItem}
              showSearch={true}
            />
          ),
          id,
          label,
          props: {
            style: { width: '100%' },
            placeholder: messages('common.select')/*请选择*/,
          },
          tagParser: value => {
            let str = '';
            value.forEach(item => {
              str += `; ${item.code}`;
            })
            return str;
          },
          parser: value => {
            if(value){
              value = value.map(item => {
                return item.code;
              })
              return {[id]: JSON.stringify(value)};
            }
          },
        }
      },
      'source': ({ label, id }) => {
        const rowChildren = [
          {
            label: messages('finance-7.key292')/*滴滴*/,
            value: "滴滴"
          },
          {
            label: messages('finance-7.key293')/*神州*/,
            value: "神州"
          }
        ];
        const children = rowChildren.map(item => <Option key={item.value}>{item.label}</Option>);
        return {
          label,
          id,
          component: 'Select',
          props: {
            style: { width: '100%' },
            placeholder: messages('common.select')/*请选择*/
          },
          children,
          tagParser: commonTagParser(rowChildren)
        }
      },
      'payee_type_list': ({ label, id }) => {
        const rowChildren = [
          {
            label: messages('finance-7.key298')/*供应商*/,
            value: "1001"
          },
          {
            label: messages('finance-7.key299')/*员工*/,
            value: "1002"
          },
        ];
        const children = rowChildren.map(item => <Option key={item.value}>{item.label}</Option>);
        return {
          label,
          id,
          component: 'Select',
          props: {
            style: { width: '100%' },
            onChange: (e) => cascadeHandler.call(this, 'payee_type_list')(context, e),
            placeholder: messages('common.select')/*请选择*/
          },
          children,
          tagParser: commonTagParser(rowChildren)
        }
      },
      'department': ({ label, id }) => {
        return {
          ...departmentObj,
          label,
          id,
          parser: value => value && value.department && value.department[0] ? {
            [id]: value.department.map(item => item.departmentCode),
            isIncludeSubDept: value.isIncludeChildren === false ? 'N' :'Y'
          } : null,
        }
      },
      'expense_department_code': ({ label, id }) => {
        return {
          ...departmentObj,
          label,
          id,
          parser: value =>value && value.department && value.department[0] ? {
            [id]: value.department.map(item => item.departmentCode),
            isIncludeExpenseSubDept: value.isIncludeChildren === false ? 'N' :'Y'
          } : null,
        };
      },
        'books': ({ label, id }) => {
        return {
          label,
          id,
          component: 'Chooser',
          props: {
            type: 'select_set_of_books',
            labelKey: 'setOfBooksName_functionalCurrencyCode',
            valueKey: 'setOfBooksId',
            single: true,
            onChange: (e) => cascadeHandler.call(this, 'books')(context, e)
          }
        }
      },
      'legal': ({ label, id }) => {
        return {
          label,
          id,
          component: 'Chooser',
          props: {
            type: 'corporation_entity',
            labelKey: 'companyName',
            valueKey: 'companyReceiptedOID',
            onlyNeed: 'companyReceiptedOID',
            single: true
          }
        }
      },
      'company': ({ label, id, dependencyCode }) => {
        if (dependencyCode === 'books') {
          let { setOfBooksId, placeholder } = setOfBooksIdAndPlaceholderFactory(context);
          return {
            label,
            id,
            component: 'Chooser',
            props: {
              type: 'auto_audit_add_company',
              labelKey: 'name',
              valueKey: 'companyOID',
              onlyNeed: 'companyOID',
              single: false,
              placeholder,
              listExtraParams: {
                setOfBooksId
              }
            }
          }
        } else {
          return {
            label,
            id,
            component: 'Chooser',
            props: {
              type: 'all_company_with_legal_entity',
              labelKey: 'companyName',
              valueKey: 'companyOID',
              onlyNeed: 'companyOID',
              single: false
            }
          }
        }
      },
      'rejecter': ({ label, id }) => {
        return {
          label,
          id,
          component: 'Chooser',
          props: {
            type: 'user',
            labelKey: 'fullName',
            valueKey: 'userOID',
            onlyNeed: 'userOID',
            single: false,
            listExtraParams: { status: 'all' }
          }
        }
      },
      'borrower': ({ label, id, dependencyCode }) => {
        if (dependencyCode === 'payee_type_list') {
          let payeeType,
            { advancedTableRef } = context,
            disabled = false,
            placeholder = messages('common.select')/*请选择*/,
            type,
            labelKey,
            valueKey,
            onlyNeed;

          // 直接从advancedTableRef取值，似乎取不到，或者是修改之前的值
          if (advancedTableRef) {
            let payeeTypeValue = advancedTableRef.getFieldValue(this.codeToName.payee_type_list || 'payee_type');
            payeeTypeValue && (payeeType = payeeTypeValue);
          }

          changeParams && (payeeType = changeParams);

          if (payeeType === '1002') { // 人
            type = 'user';
            labelKey = 'fullName';
            valueKey = 'id';
            onlyNeed = 'id';
          } else if (payeeType === '1001') {  // 供应商
            type = 'finance_vendor';
            labelKey = 'venNickname';
            valueKey = 'id';
            onlyNeed = 'id';
          }

          if (!payeeType) {
            disabled = true;
            placeholder = messages('finance-7.key244')/*请先选择借款方类型*/
          }

          return {
            label,
            id,
            component: 'Chooser',
            props: {
              placeholder,
              disabled,
              type,
              labelKey,
              valueKey,
              onlyNeed,
              single: true,
            }
          }
        } else {
          return {
            label,
            id,
            component: 'Chooser',
            props: {
              type: 'user',
              labelKey: 'fullName',
              valueKey: 'userOID',
              onlyNeed: 'userOID',
              single: true,
            }
          }
        }
      },
      'form_oid_list': ({ label, id }) => {
        return {
          label,
          id,
          component: 'Chooser',
          props: {
            type: 'form_name_form_oid_list',
            labelKey: 'formName',
            valueKey: 'formOID',
            onlyNeed: 'formOID',
            listExtraParams: { formTypeList: "2001,4100" }
          }
        }
      },
      'tr_ea_form_oid_list': ({ label, id }) => {
        return {
          label,
          id,
          component: 'Chooser',
          props: {
            type: 'form_name_form_oid_list',
            labelKey: 'formName',
            valueKey: 'formOID',
            onlyNeed: 'formOID',
            listExtraParams: { formTypeList: "2001,2002" }
          }
        }
      },
      'tr_form_oid_list': ({ label, id }) => {
        return {
          label,
          id,
          component: 'Chooser',
          props: {
            type: 'form_name_form_oid_list',
            labelKey: 'formName',
            valueKey: 'formOID',
            onlyNeed: 'formOID',
            listExtraParams: { formTypeList: "2002" }
          }
        }
      },
      'rejectnode': commonSelectFactory({ getParams: 5004 }),
      'currency': ({ label, id, dependencyCode }) => {
        if (dependencyCode === 'books') {
          let { setOfBooksId, placeholder } = setOfBooksIdAndPlaceholderFactory(context);
          return {
            label,
            id,
            component: 'Chooser',
            props: {
              type: 'currency_by_setofbooks',
              valueKey: 'currencyCode',
              onlyNeed: 'currencyCode',
              single: true,
              placeholder,
              listExtraParams: {
                enabled: true,
                language: 'zh_cn',
                setOfBooksId
              }
            }
          }
        } else {
          return {
            label,
            id,
            component: 'Selector',
            props: {
              selectorItem: {
                service: () => getValueCurrency(),
                label: 'label',
                key: 'value'
              }
            }
          }
        }
      },
      'auto_audit': ({label, id}) => {
        const items = [
          {
            label: messages('finance-7.key305')/*不通过*/,
            value: "0"
          },
          {
            label: messages('common.pass')/*通过*/,
            value: "1"
          }
        ]
        let children = items.map(item => <Option key={item.value}>{item.label}</Option>)
        let placeholder = messages('common.select')/*请选择*/;
        return {
          label,
          id,
          component: 'Select',
          props: {
            mode: "multiple",
            style: { width: '100%' },
            placeholder,
          },
          parser: value => {
            if (value && value.length) {
              return { [id]: value }
            }
            return { [id]: undefined }
          },
          children: children,
          tagParser: (value) => {
            let tag = ""
            value.map((val, index) => {
              let label = (items.find(item => item.value === val) || {}).label
              tag = `${tag}${label}${(index != value.length - 1) ? " " : ""}`
            })
            return tag
          },
        }
      },
      'inv_type': commonSelectFactory({ getMethod: getInvoiceType, multiple: true }),
      'repayment_type_list': commonSelectFactory({ getParams: 5026 }),
      'payment_type_list': commonSelectFactory({ getParams: 5043, multiple: true }),
      'document_type_list': commonSelectFactory({ getParams: 5044, multiple: true }),
      'payment_status_list': commonSelectFactory({ getParams: 5045, multiple: true }),
      'repayment_status_list': commonSelectFactory({ getParams: 5025, multiple: true }),
      'invoice': commonSelectFactory({ getParams: 5006 }),
      'form_type_list': commonSelectFactory({ getParams: 5024 }),
      'reimb_status': commonSelectFactory({ getMethod: getErStatus, multiple: true }),
      'report_status_add_vendor': commonSelectFactory({ getMethod: getErStatus, multiple: true, getParams: true }),
      'loan_status': commonSelectFactory({ getParams: 5011, multiple: true }),
      'app_status': commonSelectFactory({ getParams: 5010, params: {isAll: false}, multiple: true }),
      'reimbursement_type': commonSelectFactory({ getParams: 5007 }),
      'application_type': commonSelectFactory({ getParams: 5008 }),
      'ta_ea_application_type': commonSelectFactory({ getParams: 5042 }),
      'trip': commonSelectFactory({ getParams: 5009 }),
      'inv_status': commonSelectFactory({ getParams: 5005 }),
      'inv_check_result': commonSelectFactory({ getParams: 5003, multiple: true }),
      'compliant': commonSelectFactory({ getParams: 5013 }),
      'corp_card_status': commonSelectFactory({ getParams: 5014, multiple: true }),
      'trainOrderTypeList': commonSelectFactory({ getParams: 5064 }),
      'flight_order_status_code': commonSelectFactory({ getParams: 70001 }),
      'flight_detail_order_type': commonSelectFactory({ getParams: 70002 }),
      'hotel_order_status_code': commonSelectFactory({ getParams: 70003 }),
      'act_nam': ({ label, id }) => {
        return {
          label,
          id,
          component: 'Chooser',
          props: {
            type: 'user',
            labelKey: 'fullName',
            valueKey: 'userOID',
            onlyNeed: 'userOID',
            single: true,
          }
        }
      },

      'hotel_order_type': commonSelectFactory({ getParams: 5021 }),
      'flight_order_type': commonSelectFactory({ getParams: 5020 }),
      'invoice_tag_list': commonSelectFactory({ getMethod: getExpenseLabels }),
      'user_oid': ({ label, id }) => {
        return {
          label,
          id,
          component: 'Chooser',
          props: {
            type: 'user',
            labelKey: 'fullName',
            valueKey: 'userOID',
            onlyNeed: 'userOID',
            single: true,
          }
        }
      },
      'form_label_list': commonSelectFactory({ getMethod: getDocLabels, multiple: true }),
      'receipt_status': commonSelectFactory({ getParams: 5031 }),
      'receipt_date': commonComponentFactory('DateRangePicker', ...dateParserAndFormatter),
      'expense_create_date': commonComponentFactory('DateRangePicker', ...dateParserAndFormatter),
      'expense_receipt_date': commonComponentFactory('DateRangePicker', ...dateParserAndFormatter),
      'form_name_list': ({ label, id, dependencyCode }) => {
        if (dependencyCode === 'books') {
          let { setOfBooksId } = setOfBooksIdAndPlaceholderFactory(context);
          return {
            label,
            id,
            component: <FormTypeSelector
              title={messages('common.document.name')/*单据名称*/}
              setOfBooksId={setOfBooksId}
            />,
            tagParser: commonMultipleTagParser('formName')
          }
        } else {
          return {
            label,
            id,
            component: 'Searcher',
            props: {
              type: 'authority_form',
              descriptionKey: 'companyName',
              labelKey: 'formName',
              valueKey: 'formOID',
              listExtraParams: { formType: 1002 }
            }
          }
        }
      },
      'payment_type': commonSelectFactory({ getParams: 5032 }),
      'loan_bill_type': ({ label, id }) => {
        return {
          label,
          id,
          component: 'Chooser',
          props: {
            type: 'authority_form',
            labelKey: 'formName',
            valueKey: 'formOID',
            onlyNeed: 'formOID',
            listExtraParams: { entityType: 3001 }
          }
        }
      },
      'report_type_add_vendor': ({ label, id }) => {
        let { setOfBooksId, placeholder } = setOfBooksIdAndPlaceholderFactory(context);
        return {
          label,
          id,
          component: 'Chooser',
          props: {
            type: 'report_type_add_vendor',
            labelKey: 'formName',
            valueKey: 'formOID',
            onlyNeed: 'formOID',
            single: false,
            placeholder,
            listExtraParams: {
              "formTypeList": [3001, 3002, 3003],
              page: 0,
              size: 1000,
              '0000': "0000",
              setOfBooksId
            }
          }
        }
      },
      'cost': ({ label, id }) => {
        let { setOfBooksId } = setOfBooksIdAndPlaceholderFactory(context);
        return {
          label,
          id,
          component: <CostCenterItemSelectForReport
            title={messages('finance-7.key255')/*成本中心项*/}
            setOfBooksId={setOfBooksId}
            onChange={this.onConfirmCostCenterItem}
          />,
          tagParser: commonMultipleTagParser()
        }
      },
      'cost_center_code': ({ label, id }) => {
        let { setOfBooksId, placeholder } = setOfBooksIdAndPlaceholderFactory(context);
        return {
          label,
          id,
          component: 'Chooser',
          props: {
            type: 'select_cost_center_by_sobid',
            labelKey: 'name',
            valueKey: 'id',
            single: false,
            placeholder,
            listExtraParams: {
              setOfBooksId
            }
          }
        }
      },
      'expense_type': ({ label, id }) => {
        return {
          label,
          id,
          component: 'Chooser',
          props: {
            type: 'available_expense_type',
            labelKey: 'name',
            valueKey: 'id',
            single: false
          }
        }
      },
      'cost_center_item_code_from_to': ({ label, id }) => {
        let { setOfBooksId, placeholder } = setOfBooksIdAndPlaceholderFactory(context);
        return {
          label,
          id,
          component: <NewCostCenterSelector
            title={messages('finance-7.key155')/*成本中心*/}
            setOfBooksId={setOfBooksId}
            placeholder={placeholder}
          />,
          tagParser: value => messages('common.total.selected',{arg1: value.length})/*已选 {arg1} 条*/
        }
      },
      'exp_rpt_bag': ({ label, id }) => {
        return Object.assign(expBagCode, {
          id,
          label,
          parser: undefined
        })
      },
      'payee_type_and_id': ({ label, id }) => {
        return Object.assign(PayeeTypeAndIdSelector, {
          id,
          label,
        })
      },
      'contain_choose_form_labels': commonLabelsSelectorFactory(getDocLabels),
      'contain_choose_receipt_labels': commonLabelsSelectorFactory(getReceiptLabelTypes),
      'contain_choose_invoice_labels': commonLabelsSelectorFactory(getExpenseLabels),
      'document_company': ({ label, id, dependencyCode }) => {
        if (dependencyCode === 'books') {
          let { setOfBooksId, placeholder } = setOfBooksIdAndPlaceholderFactory(context);
          return {
            label,
            id,
            component: 'Chooser',
            props: {
              type: 'auto_audit_add_company',
              labelKey: 'name',
              valueKey: 'companyOID',
              onlyNeed: 'companyOID',
              single: false,
              placeholder,
              listExtraParams: {
                setOfBooksId
              }
            }
          }
        } else {
          return {
            label,
            id,
            component: 'Chooser',
            props: {
              type: 'all_company_with_legal_entity',
              labelKey: 'companyName',
              valueKey: 'companyOID',
              onlyNeed: 'companyOID',
              single: false
            }
          }
        }
      },
      'document_department': ({ label, id }) => {
        return {
          ...departmentObj,
          label,
          id,
          parser: value =>value && value.department && value.department[0] ? {
            [id]: value.department.map(item => item.departmentCode),
            isIncludeDocumentSubDept: value.isIncludeChildren === false ? 'N' :'Y'
          } : null,
        };
      },
      'default': commonComponentFactory()
    };

    // 供initFactory及update方法使用
    const itemFactory = ({ code, label, name, dependencyCode }) => {
      let mapItem = DEFAULT_CODE_MAP[code] || DEFAULT_CODE_MAP.default;
      let searchItem = mapItem({ label, id: name, dependencyCode });

      // 通用初始化值处理
      let initialValueFactory = searchFormInitialValueFactory[code];
      if (initialValueFactory) {
        searchItem.initialValue = typeof initialValueFactory === 'function'
          ? initialValueFactory({ context, code, name })
          : initialValueFactory;
      }


      // 各报表的初始化值
      let privateInitialValueFactory = searchItemInitialValue[code];
      if (privateInitialValueFactory) {
        searchItem.initialValue = typeof privateInitialValueFactory === 'function'
          ? privateInitialValueFactory({ context, code, name })
          : privateInitialValueFactory;
      }
      privateInitialValueFactory = searchItemInitialValueByName[name] || undefined;
      if (privateInitialValueFactory) {
        searchItem.initialValue = typeof privateInitialValueFactory === 'function'
          ? privateInitialValueFactory({ context, code, name })
          : privateInitialValueFactory;
      }

      // 各报表针对筛选项初始化处理的私有逻辑
      if (searchItemHandler[code]) {
        searchItem = searchItemHandler[code](searchItem)
      }

      return searchItem
    };

    // 初次时生成searchItem的方法
    // 与update方法的区别在于做了些初始化工具的步骤
    const initFactory = (item) => {
      /**
       * 注意这里解构之后的映射关系
       * criteriaCode => code
       * criteriaName => label
       * criteriaPropName => name
       * dependecyCriteriaCode => dependencyCode
       */
      let {
        criteriaCode: code,
        criteriaName: label,
        criteriaPropName: name,
        dependecyCriteriaCode: dependencyCode,
      } = item;

      /**
       * 保存code和name的映射
       * 但实际上code与name是一对多的关系
       *
       * 详细说一下为什么
       * {
       *  criteriaCode: "form_label_list",
       *  criteriaName: "label_code"
       * }
       * form_label_list用于表示使用什么筛选器
       * 但是实际上后端接收的值是
       * {
       *     label_code: ""
       * }
       * 导致老的代码中所有检验和值处理的逻辑全部是通过criteriaName处理的
       * 这块逻辑我没法把它转换成通过criteriaCode处理（几十种筛选器分布在几十个报表中
       * 希望后续有人能做到
       *
       * 所以保存一个映射关系用于中间级联的处理
       */
      this.codeToName[code] = name;
      this.nameToCode[name] = code;
      this.nameToLabel[name] = label;

      // 收集code依赖
      if (dependencyCode) {
        if (Array.isArray(this.dependencyMap[dependencyCode])) {
          this.dependencyMap[dependencyCode].push(code);
        } else {
          this.dependencyMap[dependencyCode] = [code];
        }
        this.codeToDependency[code] = dependencyCode;
      }

      return itemFactory({ code, label, name, dependencyCode })
    };

    // 级联更新searchItem时的方法
    const update = (item) => {
      let { id: name, label } = item;
      let code = this.nameToCode[name];
      let dependencyCode = this.codeToDependency[code];
      return itemFactory({ code, label, name, dependencyCode })
    };

    if (searchFormItem) {
      return update(searchFormItem)
    } else {
      return list.map((item) => initFactory(item));
    }
  },

  // 初始值，如果是函数则会传入context执行
  searchFormInitialValueFactory: {
    'date': [currentTimeBeforeThree, currentTime],
    'date_month': [currentTimeBeforeThree, currentTime],
    'slave_date_default': [currentTimeBeforeThree, currentTime],
    'year': todayYear,
    'cost_center_item_status': 'all',
    'is_vat_invoice': '2',
    'books': ({ context }) => [getBooksDefaultValue(context)],
    'contain_choose_receipt_labels': { contains: '1001' },
    'contain_choose_form_labels': { contains: '1001' },
    'contain_choose_invoice_labels':{ contains: '1001' }
  },

  commonCascadeHandler({ context, e, code, advancedTableRef }) {
    let depArr = this.dependencyMap[code];
    if (!depArr || !depArr.length) return;
    let { searchForm } = context.state;
    let resetObject = {};
    depArr.forEach(code => {
      let { value, index } = this.getSearchItemFromSearchFormByCode(searchForm, code);
      searchForm[index] = this.searchFormFactory({ context, searchFormItem: value, changeParams: e });
      let name = this.codeToName[code];
      resetObject[name] = undefined;
    });
    context.setState({
      searchForm
    }, () => {
      advancedTableRef.setFieldsValue(resetObject)
    });
  },

  // 级联处理入口
  cascadeHandler(code) {
    const cascadeHandlerMap = {
      'books': (context, e) => {
        let depArr = this.dependencyMap['books'];
        if (!depArr || !depArr.length) return;
        let { advancedTableRef } = context;
        this.commonCascadeHandler({ context, e, code: 'books', advancedTableRef });

        let oldValue = advancedTableRef.getFieldValue(this.codeToName.books);
        if (oldValue && oldValue[0]) {
          message.warn(messages('finance-7.key167')/*请重选依赖账套的搜索条件*/);
        }
      },
      'payee_type_list': (context, e) => {
        let depArr = this.dependencyMap['payee_type_list'];
        if (!depArr || !depArr.length) return;
        let { advancedTableRef } = context;
        this.commonCascadeHandler({ context, e, code: 'payee_type_list', advancedTableRef });

        let oldValue = advancedTableRef.getFieldValue(this.codeToName.payee_type_list);
        if (oldValue) {
          message.warn(messages('finance-7.key306')/*请重新选择依赖借款方类型的搜索条件*/);
        }
      }
    };
    return cascadeHandlerMap[code]
  },

  /**
   * 搜索之前的校验及数据转换
   * @param params
   * @param context
   */
  searchParamsTransfer({ params, context }) {
    let keys = Object.keys(params);
    let length = keys.length;
    let index = 0;
    let result = {};
    let error;
    const commonDateValidate = ({ value, label }) => {
      if (!value || !value.length || !value[0] || !value[1]) {
        return label ? messages('finance-7.key307',{arg1: label})/*请选择{arg1}*/ : messages('finance-7.key267')/*请选择时间*/
      }
      if (checkDateDuration(value[0], value[1])) {
        return messages('finance-7.key269')/*查询时间跨度不能超过12个月*/
      }
    };

    // 返回true则表示校验失败，停止搜索
    const validateCodeMap = {
      'books': ({ value }) => {
        if (!value || !value.length) {
          return messages('finance-7.key168')/*账套不能为空*/
        }
      },
      'date': commonDateValidate,
      'date_month': commonDateValidate
    };

    const validateNameMap = {};
    // 当前报表私有逻辑载体
    const { currentReportPrivate } = context.state;
    const {
      validateCodeMap: privateValidateCodeMap = {},
      validateNameMap: privateValidateNameMap = {},
    } = currentReportPrivate;

    /**
     * zl的处理方法，我也不知道怎么转换成code去处理
     * 我倾向于一个筛选器如何选值以及如何将值返回给后端，都用code去处理，保证前端开发更加简洁明了
     * 在我的理解相同的筛选器选出来的值返回给后端的形式也应该是一致
     * 但是zl采取的是code决定使用什么筛选器、name决定如何将值返回给后端
     * 不敢苟同，但是我也没法去修改这一块逻辑
     * 下面是zl的注释，看得懂的就看吧
     *
     * 支持多选
     * task 25884
     * 每一行代表一个选择器，多个参数
     * 支持多选，且传字符串数组
     * */
    const supportMultipleArr = [
      'reimb_status',//报销单状态
      'inv_check_result', 'check_result',//发票检验结果  发票检验结果返回码  两个查询参数对应一个搜索器
      'receipt_type_no',//发票类型
      'company_oid', 'applicant_company_oid', 'payment_company_oid', 'applicant_com_oid', 'booker_company_oid',//公司
      'department_code', 'applicant_dept_code', 'department_name', 'applicant_department_oid',//部门
      'expense_dept_number', // 费用承担部门
      'receipt_label_types',//发票标签
      'applicant_oid', 'rejecter_oid', 'approver_oid', 'principal_oid', //被代理人//申请人
      'collector',  // 收单人
      'drawee_oid',  // 付款人
      'reimb_audit_approver', 'audit_approver_oid',  // 审核通过人
      'report_type_add_vendor', 'form_oid',//带供应商的报销类型code
      'report_status_add_vendor', 'status',//带供应商的报销状态code
      'app_status', 'STATUS', 'business_card_status',
      'label_code', 'label_types', // 单据标签
      'created_by_oid' // 创建人
    ];


    /**
     * 下面是我加的
     * 所以是根据code去处理的
     * 所有dateRangePicker出来的值都走这段逻辑
     */
    const dateRangeArr = [
      'date',
      'slave_date_default',
      'slave_date',
      'receipt_date',
      'expense_create_date',
      'expense_receipt_date',
    ];

    function commonTransfer({ name, code, value }) {
      if (dateRangeArr.includes(code)) {
        if (value && value.length) {
          return JSON.stringify(value.map(date => {
            let result = moment(date).format("YYYY-MM-DD");
            return result !== "Invalid date" ? result : null
          }));
        } else {
          return undefined
        }
      }

      if (supportMultipleArr.includes(name)) {
        return value ? JSON.stringify(value) : undefined
      }

      return Array.isArray(value) ? value[0] : value
    }

    // 对应原travel-report中对于params['form-oid']的处理
    const formOidTransfer = ({ value }) => {
      if (value) {
        if (Array.isArray(value)) {
          return JSON.stringify(value)
        } else {
          return JSON.stringify(value.split(','))
        }
      }
      return undefined
    };

    const commonArrayTransfer = ({value}) => {
      return value && value.length ? JSON.stringify(value) : undefined
    };

    // code为key的转换器map，优先级高于commonTransfer
    const transferMap = {
      'year_month_date': ({ value }) => {
        return value === "Invalid date" || !value ? undefined : moment(value).format('YYYY-MM');
      },
      'date_month': ({ value }) => {
        return value && value.length ? JSON.stringify(value.map(item => {
          return item === "Invalid date" || !item ? undefined : moment(item).format('YYYY-MM');
        })) : undefined;
      },
      'cost_center_item_code_from_to': ({ value }) => {
        return value && value.length ? JSON.stringify(value) : undefined;
      },
      'cost_center_code': ({ value }) => {
        return value && value.length ? JSON.stringify(value.map(item => {
          return item.code;
        })) : undefined;
      },
      'form_name_list': ({ value }) => {
        return value && value.length ? JSON.stringify(value.map(item => {
          return item.formOID;
        })) : undefined;
      },
      'books': ({ value }) => {
        return value && value[0] ? value[0].setOfBooksId : undefined;
      },
      'cost': ({ value }) => {
        return value && value[0] ? value[0].costCenterItemOID : undefined;
      },
      'form_oid_list': formOidTransfer,
      'report_type_add_vendor': formOidTransfer,
      'tr_ea_form_oid_list': formOidTransfer,
      'loan_bill_type': formOidTransfer,
      'expense_type': ({ value }) => {
        if (value) {
          return Array.isArray(value) ? JSON.stringify(value.map(item => item.id)) : value.id
        }
        return undefined
      },
      'exp_rpt_bag': ({ value }) => {
        const { isRefBagCode, expBagCode: bagCode } = value || {};
        const bagFlag = isRefBagCode === '1001';
        return isRefBagCode ? JSON.stringify({
          bagFlag,
          bagCode
        }) : undefined
      },
      'payee_type_and_id': ({ value }) => {
        let { payeeType, payeeId } = value || {};
        if (payeeId && payeeId[0]) {
          payeeId = payeeId[0].id
        } else {
          payeeId = undefined
        }
        return payeeType ? JSON.stringify({
          payeeType,
          payeeId
        }) : undefined
      },
      'contain_choose_form_labels': labelsSelectorTransfer,
      'contain_choose_receipt_labels': labelsSelectorTransfer,
      'contain_choose_invoice_labels': labelsSelectorTransfer,
      'payment_type_list': commonArrayTransfer,
      'document_type_list': commonArrayTransfer,
      'payment_status_list': commonArrayTransfer,
      'rejecter': commonArrayTransfer,
      'document_department': commonArrayTransfer,
      'auto_audit': ({value}) => JSON.stringify(value),
    };

    try {
      let errorInfo= []
      let hasOtherSearchParams= false
      while (index < length) {
        let name = keys[index];
        let value = params[name];
        let code = this.nameToCode[name];
        let label = this.nameToLabel[name];
        // console.log(name + '-----' + label + code)
        // console.log(JSON.stringify(value))
        let validate = validateCodeMap[code];
        // 依据code的validate
        if (validate) {
          let innerError = validate({ value, params, label });
          if(innerError){
            if(code === 'books'){
              error= innerError;
              message.warn(innerError);
              break;
            }else{
              errorInfo.push({
                code: code,
                error: innerError
              })
              index++;
              continue;
            }
          }

        }
        // 依据name的validate
        validate = validateNameMap[name];
        if (validate) {
          error = validate({ value, params, label });
          if (error) {
            message.warn(error);
            break;
          }
        }

        let privateValidate = privateValidateCodeMap[code];
        // 依据code的privateValidate
        if (privateValidate) {
          error = privateValidate({ value, params, label });
          if (error) {
            message.warn(error);
            break;
          }
        }
        // 依据name的privateValidate
        privateValidate = privateValidateNameMap[name];
        if (privateValidate) {
          error = privateValidate({ value, params, label });
          if (error) {
            message.warn(error);
            break;
          }
        }

        let transfer = transferMap[code];

        // transfer
        if (transfer) {
          result[name] = transfer({ name, code, value });
        } else {
          result[name] = commonTransfer({ name, code, value });
        }
        if(name !== 'set_of_books_id' && result[name]){
          hasOtherSearchParams= true
        }
        index++;
      }

      if(errorInfo.length > 0 && !hasOtherSearchParams){
        let error= errorInfo[0].error
        if (error) {
          message.warn(error);
        }
        return Promise.reject({ type: "validateError", message: error })
      }

      return error ? Promise.reject({ type: "validateError", message: error }) : Promise.resolve(result);
    } catch (e) {
      console.error(e);
      return Promise.reject(e);
    }
  },

  //根据后端返回的 reportColumnDTOList，或者 reportColumnCustomizedDTOList ，获取报表的列
  getReportTableColumn({ list, context }) {
    const { currentReportPrivate } = context.state;
    const { columnsHandler } = currentReportPrivate;
    let newArr = [];
    let length = list.length;
    // 用于去重，后端有时候出错会返回重复的项，导致前端抛出大量warning
    let existMap = new Map([]);
    for (let i = 0; i < length; i++) {
      let item = list[i];
      const { columnPropName, hide, columnDisplayName } = item;
      if (!hide && !existMap.has(columnPropName)) {
        item.title = <Popover placement="topLeft" content={columnDisplayName}>{columnDisplayName}</Popover>;
        item.dataIndex = columnPropName;
        item.render = (text) => {
          if (item.dataType === 'bigdecimal' && text !== undefined && text !== null)
            text = context.filterMoney(text)
          const content = text !== undefined && text !== null ?
            <Popover
              content={text}
              placement={item.dataType === 'bigdecimal' ? 'topRight' : 'topLeft'}>
              {text}
            </Popover> : '-';
          return <span>{content}</span>;
        }
        item.width = 200;
        newArr.push(item);
        existMap.set(item.dataIndex, true);
      }
    }
    existMap.clear();
    existMap = null;

    // 报表私有的列处理
    if (columnsHandler) {
      newArr = columnsHandler({ list: newArr, context })
    }
    return newArr
  },

  // 用于字段设置的columns
  dataColumnsByMan(arr) {
    return arr.map(item => {
      item.editName = false;
      item.editHide = false;
      return item;
    })
  },

  // 获取报表结构
  getReportDetail({ reportId, context }) {
    let param = {
      id: reportId,//报表id
    };
    this.resetMaps();
    return new Promise((resolve, reject) => {
      httpFetch.get(config.baseUrl + '/report/api/report/getReport', param)
        .then((res) => {
          let data = res.data;
          //data字段解释
          //reportCriteriaDTOList  是顶部查询字段
          //reportCriteriaCustomizedDTOList 有就显示自定义的是自定义查询字段，有就显示自定义的

          //reportColumnDTOList 是报表的列
          //reportColumnCustomizedDTOList是自定义的列，有就显示自定义的

          let search = data.reportCriteriaDTOList;//默认搜索组件
          let customSearch = data.reportCriteriaCustomizedDTOList;//自定义组件
          let column = data.reportColumnDTOList;//默认报表列
          let customColumn = data.reportColumnCustomizedDTOList;//自定义报表列

          let _reportSearch = customSearch.length > 0 ? customSearch : search;
          let reportColumn = customColumn.length > 0 ? customColumn : column;

          // 生成searchForm
          data.searchForm = this.searchFormFactory({ list: _reportSearch, context });
          data.columns = this.getReportTableColumn({ list: reportColumn, context });
          data.dataColumnsModal = this.dataColumnsByMan(reportColumn);

          resolve(res)
        })
        .catch(function (err) {
          console.error(err);
          errorMessage(err.response);
          reject(err.response);
        })
    })
  },
  //查询报表数据
  getTravelDataList(body) {
    return new Promise((resolve, reject) => {
      httpFetch.post(config.baseUrl + '/report/api/report/search', body)
        .then((response) => {
          // fix bug28893
          response.data = response.data.filter(item => {
            if (item + "" !== "null" && item + "" !== "undefined") {
              return item;
            }
          })
          resolve(response)
        })
        .catch(function (err) {
          errorMessage(err.response);
          reject(err.response);
        })
    })
  },
  //获取 审批流程平均时长
  getApproverTime(body) {
    return new Promise((resolve, reject) => {
      httpFetch.post(config.baseUrl + '/report/api/report/apprEfficiency/control', body)
        .then((response) => {
          resolve(response)
        })
        .catch(function (err) {
          errorMessage(err.response);
          reject(err.response);
        })
    })
  },
  //获取 待审批单据数量 & 平均待审批时长
  getWaitingTime(body) {
    return new Promise((resolve, reject) => {
      httpFetch.post(config.baseUrl + '/report/api/report/apprTodoEfficiency/control', body)
        .then((response) => {
          resolve(response)
        })
        .catch(function (err) {
          errorMessage(err.response);
          reject(err.response);
        });
    });
  },
  getSearchItemFromSearchFormByCode(searchForm, code) {
    let name = this.codeToName[code];
    let result = {
      value: undefined,
      index: undefined
    };
    result.value = searchForm.find((item, index) => item.id === name && ((result.index = index) || true));
    return result;
  }
}

